home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / bash / bash_108 / bash-108.zoo / bash-1.08 / trap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-19  |  11.8 KB  |  482 lines

  1. /* trap.c -- Not the trap command, but useful functions
  2.    for manipulating those objects.  The trap command is
  3.    in builtins.c */
  4.  
  5. /* Copyright (C) 1987, 1991 Free Software Foundation, Inc.
  6.  
  7. This file is part of GNU Bash, the Bourne Again SHell.
  8.  
  9. Bash is free software; you can redistribute it and/or modify it under
  10. the terms of the GNU General Public License as published by the Free
  11. Software Foundation; either version 1, or (at your option) any later
  12. version.
  13.  
  14. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  15. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  17. for more details.
  18.  
  19. You should have received a copy of the GNU General Public License along
  20. with Bash; see the file COPYING.  If not, write to the Free Software
  21. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  22.  
  23. #include "trap.h"
  24. #include "shell.h"
  25.  
  26. /* The list of things to do originally, before we started trapping. */
  27. SigHandler *original_signals[NSIG];
  28.  
  29. /* For each signal, a slot for a string, which is a command to be
  30.    executed when that signal is recieved.  The slot can also contain
  31.    DEFAULT_SIG, which means do whatever you were going to do before
  32.    you were so rudely interrupted, or IGNORE_SIG, which says ignore
  33.    this signal. */
  34. char *trap_list[NSIG];
  35.  
  36. /* A translation list so we can be polite to our users. */
  37. char *signal_names[NSIG];
  38.  
  39. /* A bitmap of signals received for which we have trap handlers. */
  40. int pending_traps[NSIG];
  41.  
  42. static int signal_names_initialized = 0;
  43.  
  44.  
  45. initialize_traps ()
  46. {
  47.   register int i;
  48.  
  49.   if (!signal_names_initialized)
  50.     {
  51.       for (i = 1; i < NSIG; i++)
  52.         {
  53.       signal_names[i] = (char *)NULL;
  54.       pending_traps[i] = 0;
  55.         }
  56.  
  57.       /* `signal' 0 is what we do on exit. */
  58.       signal_names[0] = "EXIT";
  59.  
  60. #if defined (SIGHUP)        /* hangup */
  61.       signal_names[SIGHUP] = "SIGHUP";
  62. #endif
  63.  
  64. #if defined (SIGINT)        /* interrupt */
  65.       signal_names[SIGINT] = "SIGINT";
  66. #endif
  67.  
  68. #if defined (SIGQUIT)        /* quit */
  69.       signal_names[SIGQUIT] = "SIGQUIT";
  70. #endif
  71.  
  72. #if defined (SIGILL)        /* illegal instruction (not reset when caught) */
  73.       signal_names[SIGILL] = "SIGILL";
  74. #endif
  75.  
  76. #if defined (SIGTRAP)        /* trace trap (not reset when caught) */
  77.       signal_names[SIGTRAP] = "SIGTRAP";
  78. #endif
  79.  
  80. #if defined (SIGABRT)        /*  */
  81.       signal_names[SIGABRT] = "SIGABRT";
  82. #endif
  83.  
  84. #if defined (SIGIOT)        /* IOT instruction */
  85.       signal_names[SIGIOT] = "SIGIOT";
  86. #endif
  87.  
  88. #if defined (SIGEMT)        /* EMT instruction */
  89.       signal_names[SIGEMT] = "SIGEMT";
  90. #endif
  91.  
  92. #if defined (SIGFPE)        /* floating point exception */
  93.       signal_names[SIGFPE] = "SIGFPE";
  94. #endif
  95.  
  96. #if defined (SIGKILL)        /* kill (cannot be caught or ignored) */
  97.       signal_names[SIGKILL] = "SIGKILL";
  98. #endif
  99.  
  100. #if defined (SIGBUS)        /* bus error */
  101.       signal_names[SIGBUS] = "SIGBUS";
  102. #endif
  103.  
  104. #if defined (SIGSEGV)        /* segmentation violation */
  105.       signal_names[SIGSEGV] = "SIGSEGV";
  106. #endif
  107.  
  108. #if defined (SIGSYS)        /* bad argument to system call */
  109.       signal_names[SIGSYS] = "SIGSYS";
  110. #endif
  111.  
  112. #if defined (SIGPIPE)        /* write on a pipe with no one to read it */
  113.       signal_names[SIGPIPE] = "SIGPIPE";
  114. #endif
  115.  
  116. #if defined (SIGALRM)        /* alarm clock */
  117.       signal_names[SIGALRM] = "SIGALRM";
  118. #endif
  119.  
  120. #if defined (SIGTERM)        /* software termination signal from kill */
  121.       signal_names[SIGTERM] = "SIGTERM";
  122. #endif
  123.  
  124. #if defined (SIGCLD)        /* Like SIGCHLD.  */
  125.       signal_names[SIGCLD] = "SIGCLD";
  126. #endif
  127.  
  128. #if defined (SIGPWR)        /* Magic thing for some machines. */
  129.       signal_names[SIGPWR] = "SIGPWR";
  130. #endif
  131.  
  132. #if defined (SIGPOLL)        /* For keyboard input?  */
  133.       signal_names[SIGPOLL] = "SIGPOLL";
  134. #endif
  135.  
  136. #if defined (SIGURG)        /* urgent condition on IO channel */
  137.       signal_names[SIGURG] = "SIGURG";
  138. #endif
  139.  
  140. #if defined (SIGSTOP)        /* sendable stop signal not from tty */
  141.       signal_names[SIGSTOP] = "SIGSTOP";
  142. #endif
  143.  
  144. #if defined (SIGTSTP)        /* stop signal from tty */
  145.       signal_names[SIGTSTP] = "SIGTSTP";
  146. #endif
  147.  
  148. #if defined (SIGCONT)        /* continue a stopped process */
  149.       signal_names[SIGCONT] = "SIGCONT";
  150. #endif
  151.  
  152. #if defined (SIGCHLD)        /* to parent on child stop or exit */
  153.       signal_names[SIGCHLD] = "SIGCHLD";
  154. #endif
  155.  
  156. #if defined (SIGTTIN)        /* to readers pgrp upon background tty read */
  157.       signal_names[SIGTTIN] = "SIGTTIN";
  158. #endif
  159.  
  160. #if defined (SIGTTOU)        /* like TTIN for output if (tp->t_local<OSTOP) */
  161.       signal_names[SIGTTOU] = "SIGTTOU";
  162. #endif
  163.  
  164. #if defined (SIGIO)        /* input/output possible signal */
  165.       signal_names[SIGIO] = "SIGIO";
  166. #endif
  167.  
  168. #if defined (SIGXCPU)        /* exceeded CPU time limit */
  169.       signal_names[SIGXCPU] = "SIGXCPU";
  170. #endif
  171.  
  172. #if defined (SIGXFSZ)        /* exceeded file size limit */
  173.       signal_names[SIGXFSZ] = "SIGXFSZ";
  174. #endif
  175.  
  176. #if defined (SIGVTALRM)        /* virtual time alarm */
  177.       signal_names[SIGVTALRM] = "SIGVTALRM";
  178. #endif
  179.  
  180. #if defined (SIGPROF)        /* profiling time alarm */
  181.       signal_names[SIGPROF] = "SIGPROF";
  182. #endif
  183.  
  184. #if defined (SIGWINCH)        /* window changed */
  185.       signal_names[SIGWINCH] = "SIGWINCH";
  186. #endif
  187.  
  188. #if defined (SIGLOST)        /* resource lost (eg, record-lock lost) */
  189.       signal_names[SIGLOST] = "SIGLOST";
  190. #endif
  191.  
  192. #if defined (SIGUSR1)        /* user defined signal 1 */
  193.       signal_names[SIGUSR1] = "SIGUSR1";
  194. #endif
  195.  
  196. #if defined (SIGUSR2)        /* user defined signal 2 */
  197.       signal_names[SIGUSR2] = "SIGUSR2";
  198. #endif
  199.  
  200. #if defined (SIGMSG)    /* HFT input data pending */
  201.       signal_names[SIGMSG] = "SIGMSG";
  202. #endif
  203.  
  204. #if defined (SIGPWR)    /* power failure imminent (save your data) */
  205.       signal_names[SIGPWR] = "SIGPWR";
  206. #endif
  207.  
  208. #if defined (SIGDANGER)    /* system crash imminent */
  209.       signal_names[SIGDANGER] = "SIGDANGER";
  210. #endif
  211.  
  212. #if defined (SIGMIGRATE)    /* migrate process to another CPU */
  213.       signal_names[SIGMIGRATE] = "SIGMIGRATE";
  214. #endif
  215.  
  216. #if defined (SIGPRE)    /* programming error */
  217.       signal_names[SIGPRE] = "SIGPRE";
  218. #endif
  219.  
  220. #if defined (SIGGRANT)    /* HFT monitor mode granted */
  221.       signal_names[SIGGRANT] = "SIGGRANT";
  222. #endif
  223.  
  224. #if defined (SIGRETRACT)    /* HFT monitor mode retracted */
  225.       signal_names[SIGRETRACT] = "SIGRETRACT";
  226. #endif
  227.  
  228. #if defined (SIGSOUND)    /* HFT sound sequence has completed */
  229.       signal_names[SIGSOUND] = "SIGSOUND";
  230. #endif
  231.  
  232.       for (i = 0; i < NSIG; i++)
  233.     if (signal_names[i] == (char *)NULL)
  234.       {
  235.         signal_names[i] = (char *)xmalloc (10 + strlen ("SIGJUNK"));
  236.         sprintf (signal_names[i], "SIGJUNK(%d)", i);
  237.       }
  238.     }
  239.  
  240.  
  241.   trap_list[0] = (char *)NULL;
  242.  
  243.   for (i = 1; i < NSIG; i++)
  244.     {
  245.       trap_list[i] = (char *)DEFAULT_SIG;
  246.       original_signals[i] = (SigHandler *)signal (i, SIG_DFL);
  247.       signal (i, original_signals[i]);
  248.     }
  249. }
  250.  
  251. /* Return the print name of this signal. */
  252. char *
  253. signal_name (signal)
  254.      int signal;
  255. {
  256.   if (signal > NSIG)
  257.      return ("bad signal number");
  258.   else return (signal_names[signal]);
  259. }
  260.  
  261. /* Turn a string into a signal number, or a number into
  262.    a signal number.  If STRING was "2", "SIGINT", or "INT",
  263.    then (int)2 would be returned. */
  264. int
  265. decode_signal (string)
  266.      char *string;
  267. {
  268.   int sig;
  269.  
  270.   if (sscanf (string, "%d", &sig) == 1) {
  271.     if (sig < NSIG && sig >= 0)
  272.       return (sig);
  273.     else
  274.       return (NO_SIG);
  275.   }
  276.       
  277.   for (sig = 0; sig < NSIG; sig++)
  278.      if ((stricmp (string, signal_names[sig]) == 0) ||
  279.      (stricmp (string, &(signal_names[sig])[3]) == 0))
  280.        return (sig);
  281.  
  282.   return (NO_SIG);
  283. }
  284.  
  285. /* Non-zero when we catch a trapped signal. */
  286. static int catch_flag = 0;
  287.  
  288. #if !defined (USG) && !defined (USGr4)
  289. #define HAVE_BSD_SIGNALS
  290. #endif
  291.  
  292. run_pending_traps ()
  293. {
  294.   register int sig;
  295.   extern int last_command_exit_value;
  296.   int old_exit_value;
  297.  
  298.   if (catch_flag == 0)        /* simple optimization */
  299.     return;
  300.  
  301.   catch_flag = 0;
  302.  
  303.   /* Preserve $? when running trap. */
  304.   old_exit_value = last_command_exit_value;
  305.  
  306.   for (sig = 0; sig < NSIG; sig++)
  307.     {
  308.       if (pending_traps[sig])
  309.     {
  310. #if defined (_POSIX_VERSION)
  311.       sigset_t set, oset;
  312.       sigemptyset (&set);
  313.       sigaddset (&set, sig);
  314.       sigprocmask (SIG_BLOCK, &set, &oset);
  315. #else
  316. #  if defined (HAVE_BSD_SIGNALS)
  317.       int oldmask = sigblock (sigmask (sig));
  318. #  endif
  319. #endif /* POSIX_VERSION */
  320.  
  321.       parse_and_execute (savestring (trap_list[sig]), "trap");
  322.       pending_traps[sig] = 0;
  323.  
  324. #if defined (_POSIX_VERSION)
  325.       sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
  326. #else
  327. #  if defined (HAVE_BSD_SIGNALS)
  328.       sigsetmask (oldmask);
  329. #  endif
  330. #endif /* POSIX_VERSION */
  331.     }
  332.     }
  333.  
  334.   last_command_exit_value = old_exit_value;
  335. }
  336.  
  337. sighandler
  338. trap_handler (sig)
  339.      int sig;
  340. {
  341.   if ((sig >= NSIG) ||
  342.       (trap_list[sig] == (char *)DEFAULT_SIG) ||
  343.       (trap_list[sig] == (char *)IGNORE_SIG))
  344.     programming_error ("trap_handler: Bad signal %d", sig);
  345.   else
  346.     {
  347.       catch_flag = 1;
  348.       pending_traps[sig]++;
  349.     }
  350. }
  351.  
  352. /* Set SIG to call STRING as a command. */
  353. void
  354. set_signal (sig, string)
  355.      int sig;
  356.      char *string;
  357. {
  358.   void change_signal ();
  359.  
  360.   /* A signal ignored on entry to the shell cannot be trapped or reset, but
  361.      no error is reported when attempting to do so.  -- Posix.2 */
  362.   if (original_signals[sig] == SIG_IGN)
  363.     return;
  364.  
  365. #ifdef SIGCHLD
  366.   /* Don't change the function that catches SIGCHLD, but store the command
  367.      to be executed.  It will be run from jobs.c: flush_child(). */
  368.   if (sig && (sig != SIGCHLD))
  369. #else
  370.   if (sig)
  371. #endif
  372.     signal (sig, SIG_IGN);
  373.  
  374.   change_signal (sig, savestring (string));
  375.  
  376. #ifdef SIGCHLD
  377.   /* Don't change the function that catches SIGCHLD, but store the command
  378.      to be executed.  It will be run from jobs.c: flush_child(). */
  379.   if (sig && (sig != SIGCHLD))
  380. #else
  381.   if (sig)
  382. #endif
  383.     signal (sig, trap_handler);
  384. }
  385.  
  386. /* If SIG has a string assigned to it, get rid of it.  Then give it
  387.    VALUE. */
  388. void
  389. change_signal (sig, value)
  390.      int sig;
  391.      char *value;
  392. {
  393.   if ((((int)trap_list[sig]) > 0) && (trap_list[sig] != (char *)IGNORE_SIG))
  394.     free (trap_list[sig]);
  395.   trap_list[sig] = value;
  396. }
  397.  
  398. /* Restore the default action for SIG; i.e., the action the shell
  399.    would have taken before you used the trap command. */
  400. void
  401. restore_default_signal (sig)
  402.      int sig;
  403. {
  404. #ifdef SIGCHLD
  405.   /* Don't allow the SIGCHLD signal catcher to be overridden. */
  406.   if (sig != SIGCHLD)
  407. #endif
  408.     signal (sig, original_signals[sig]);
  409.   change_signal (sig, (char *)DEFAULT_SIG);
  410. }
  411.  
  412. /* Make this signal be ignored. */
  413. void
  414. ignore_signal (sig)
  415.      int sig;
  416. {
  417. #ifdef SIGCHLD
  418.   /* Don't allow the SIGCHLD signal catcher to be overridden. */
  419.   if (sig != SIGCHLD)
  420. #endif
  421.     signal (sig, SIG_IGN);
  422.   change_signal (sig, (char *)IGNORE_SIG);
  423. }
  424.  
  425. /* Handle the calling of "trap 0".  The only sticky situation is when
  426.    the command to be executed includes an "exit".  This is why we have
  427.    to provide our own place for top_level to jump to. */
  428. void
  429. run_exit_trap ()
  430. {
  431.   if ((trap_list[0] != (char *)DEFAULT_SIG) &&
  432.       (trap_list[0] != (char *)IGNORE_SIG))
  433.     {
  434.       char *trap_command = savestring (trap_list[0]);
  435.       int code;
  436.  
  437.       change_signal (0, (char *)NULL);
  438.       code = setjmp (top_level);
  439.       if (code == 0)
  440.     parse_and_execute (trap_command, "trap");
  441.     }
  442. }
  443.       
  444. /* Reset all trapped signals to their original values.  Signals set to be
  445.    ignored with trap '' SIGNAL should be ignored, so we make sure that they
  446.    are. */
  447. void
  448. restore_original_signals ()
  449. {
  450.   register int i;
  451.  
  452.   for (i = 0; i < NSIG; i++)
  453.     {
  454.       if (trap_list[i] != (char *)DEFAULT_SIG)
  455.     {
  456.       if (trap_list[i] == (char *)IGNORE_SIG)
  457.         signal (i, SIG_IGN);
  458.       else
  459.         restore_default_signal (i);
  460.     }
  461.     }
  462. }
  463.  
  464. /* Run a trap set on SIGINT.  This is called from throw_to_top_level (), and
  465.    declared here to localize the trap functions. */
  466. run_interrupt_trap ()
  467. {
  468.   char *command;
  469.   int old_exit_value;
  470.   extern int last_command_exit_value;
  471.  
  472.   if ((trap_list[SIGINT] != (char *) DEFAULT_SIG) &&
  473.       (trap_list[SIGINT] != (char *) IGNORE_SIG))
  474.     {
  475.       command = savestring (trap_list[SIGINT]);
  476.  
  477.       old_exit_value = last_command_exit_value;
  478.       parse_and_execute (command, "interrupt trap");
  479.       last_command_exit_value = old_exit_value;
  480.     }
  481. }
  482.